home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr47 / masm.zip / ASM2.DOC < prev    next >
Text File  |  1993-04-07  |  25KB  |  429 lines

  1.  
  2.         so.  An exception is the saving and restoring of registers at
  3.         entrance to and exit from a subroutine; here, if the subroutine is
  4.         long, you should probably PUSH everything which the caller may need
  5.         saved, whether you will use the register or not, and POP it in
  6.         reverse order at the end.
  7.         Be aware that CALL and INT push return address information on the
  8.         stack and RET and IRET pop it off.  It is a good idea to become
  9.         familiar with the structure of the stack.
  10.     c.  In practice, to invoke system services you will use the INT
  11.         instruction.  It is quite possible to use this instruction effec-
  12.         tively in a cookbook fashion without knowing precisely how it
  13.         works.
  14.     d.  The transfer of control instructions (CALL, RET, JMP) deserve care-
  15.         ful study to avoid confusion.  You will learn that these can be
  16.         classified as follows:
  17.         1)  all three have the capability of being either NEAR (CS register
  18.             unchanged) or FAR (CS register changed)
  19.         2)  JMPs and CALLs can be DIRECT (target is assembled into instruc-
  20.             tion) or INDIRECT (target fetched from memory or register)
  21.         3)  if NEAR and DIRECT, a JMP can be SHORT (less than 128 bytes
  22.             away) or LONG
  23.         In general, the third issue is not worth worrying about.  On a for-
  24.         ward jump which is clearly VERY short, you can tell the assembler
  25.         it is short and save one byte of code:
  26.                    JMP SHORT  CLOSEBY
  27.         On a backward jump, the assembler can figure it out for you.  On a
  28.         forward jump of dubious length, let the assembler default to a LONG
  29.         form; at worst you waste one byte.
  30.         Also leave the assembler to worry about how the target address is
  31.         to be represented, in absolute form or relative form.
  32.     e.  The conditional jump set is rather confusing when studied apart
  33.         from the assembler, but you do need to get a feeling for it.  The
  34.         interactions of the sign, carry, and overflow flags can get your
  35.         mind stuttering pretty fast if you worry about it too much.  What
  36.         is boils down to, though, is
  37.                 JZ        means what it says
  38.                 JNZ       means what it says
  39.                 JG reater this means "if the SIGNED difference is positive"
  40.                 JA bove   this means "if the UNSIGNED difference is positive"
  41.                 JL ess    this means "if the SIGNED difference is negative"
  42.                 JB elow   this means "if the UNSIGNED difference is negative"
  43.                 JC arry   assembles the same as JB; it's an aesthetic choice
  44.  
  45. IBM PC Assembly Language Tutorial                                        10
  46.  
  47.  
  48.         You should understand that all conditional jumps are inherently
  49.         DIRECT, NEAR, and "short"; the "short" part means that they can't
  50.         go more than 128 bytes in either direction.  Again, this is some-
  51.         thing you could easily imagine to be more of a problem than it is.
  52.         I follow this simple approach:
  53.         1)  When taking an abnormal exit from a block of code, I always use
  54.             an unconditional jump.  Who knows how far you are going to end
  55.             up jumping by the time the program is finished.  For example, I
  56.             wouldn't code this:
  57.                    TEST     AL,IDIBIT       ;Is the idiot bit on?
  58.                    JNZ      OYVEY           ;Yes.  Go to general cleanup
  59.             Rather, I would probably code this:
  60.                    TEST     AL,IDIBIT       ;Is the idiot bit on?
  61.                    JZ       NOIDIOCY        ;No.  I am saved.
  62.                    JMP      OYVEY           ;Yes.  What can we say...
  63.               NOIDIOCY:
  64.             The latter, of course, is a jump around a jump.  Some would say
  65.             it is evil, but I submit it is hard to avoid in this language.
  66.         2)  Otherwise, within a block of code, I use conditional jumps
  67.             freely.  If the block eventually grows so long that the assem-
  68.             bler starts complaining that my conditional jumps are too long
  69.             I
  70.             a)  consider reorganizing the block but
  71.             b)  also consider changing some conditional jumps to their
  72.                 opposite and use the "jump around a jump" approach as shown
  73.                 above.
  74.     Enough about specific instructions!
  75. 6.  Finally, in order to use the assembler effectively, you need to know
  76.     the default rules for which segment registers are used to complete
  77.     addresses in which situations.
  78.     a.  CS is used to complete an address which is the target of a NEAR
  79.         DIRECT jump.  On an NEAR INDIRECT jump, DS is used to fetch the
  80.         address from memory but then CS is used to complete the address
  81.         thus fetched.  On FAR jumps, of course, CS is itself altered.  The
  82.         instruction counter is always implicitly pointing in the code seg-
  83.         ment.
  84.     b.  SS is used to complete an address if BP is used in its formation.
  85.         Otherwise, DS is always used to complete a data address.
  86.     c.  On the string instructions, the target is always formed from ES and
  87.         DI.  The source is normally formed from DS and SI.  If there is a
  88.         segment prefix, it overrides the source not the target.
  89.  
  90. IBM PC Assembly Language Tutorial                                        11
  91.  
  92.  
  93. Learning about DOS
  94. __________________
  95. Learning about DOS
  96. Learning about DOS
  97. Learning about DOS
  98. I think the best way to learn about DOS internals is to read the technical
  99. appendices in the manual.  These are not as complete as we might wish, but
  100. they really aren't bad; I certainly have learned a lot from them.  What you
  101. don't learn from them you might eventually learn via judicious disassembly
  102. of parts of DOS, but that shouldn't really be necessary.
  103. From reading the technical appendices, you learn that interrupts 20H
  104. through 27H are used to communicate with DOS.  Mostly, you will use inter-
  105. rupt 21H, the DOS function manager.
  106. The function manager implements a great many services.  You request the
  107. individual services by means of a function code in the AH register.  For
  108. example, by putting a nine in the AH register and issuing interrupt 21H you
  109. tell DOS to print a message on the console screen.
  110. Usually, but by no means always, the DX register is used to pass data for
  111. the service being requested.  For example, on the print message service
  112. just mentioned, you would put the 16 bit address of the message in the DX
  113. register.  The DS register is also implicitly part of this argument, in
  114. keeping with the universal segmentation rules.
  115. In understanding DOS functions, it is useful to understand some history and
  116. also some of the philosophy of MS-DOS with regard to portability.  General-
  117. ly, you will find, once you read the technical information on DOS and also
  118. the IBM technical reference, you will know more than one way to do almost
  119. anything.  Which is best?  For example, to do asynch adapter I/O, you can
  120. use the DOS calls (pretty incomplete), you can use BIOS, or you can go
  121. directly to the hardware.  The same thing is true for most of the other
  122. primitive I/O (keyboard or screen) although DOS is more likely to give you
  123. added value in these areas.  When it comes to file I/O, DOS itself offers
  124. more than one interface.  For example, there are four calls which read data
  125. from a file.
  126. The way to decide rationally among these alternatives is by understanding
  127. the tradeoffs of functionality versus portability.  Three kinds of porta-
  128. bility need to be considered:  machine portability, operating system porta-
  129. bility (for example, the ability to assemble and run code under CP/M 86)
  130. and DOS version portability (the ability for a program to run under older
  131. versions of DOS>.
  132. Most of the functions originally offered in DOS 1.0 were direct descendents
  133. of CP/M functions; there is even a compatibility interface so that programs
  134. which have been translated instruction for instruction from 8080 assembler
  135. to 8086 assembler might have a reasonable chance of running if they use
  136. only the core CP/M function set.  Among the most generally useful in this
  137. original compatibility set are
  138.  
  139.  
  140.  
  141. IBM PC Assembly Language Tutorial                                        12
  142.  
  143.  
  144.   09   --  print a full message on the screen
  145.   0A   --  get a console input line with full DOS editing
  146.   0F   --  open a file
  147.   10   --  close a file (really needed only when writing)
  148.   11   --  find first file matching a pattern
  149.   12   --  find next file matching a pattern
  150.   13   --  erase a file
  151.   16   --  create a file
  152.   17   --  rename a file
  153.   1A   --  set disk transfer address
  154. The next set provide no function above what you can get with BIOS calls or
  155. more specialized DOS calls.  However, they are preferable to BIOS calls
  156. when portability is an issue.
  157.   00   --  terminate execution
  158.   01   --  read keyboard character
  159.   02   --  write screen character
  160.   03   --  read COM port character
  161.   04   --  write COM port character
  162.   05   --  print a character
  163.   06   --  read keyboard or write screen with no editing
  164. The standard file I/O calls are inferior to the specialized DOS calls but
  165. have the advantage of making the program easier to port to CP/M style sys-
  166. tems.  Thus they are worth mentioning:
  167.   14   --  sequential read from file
  168.   15   --  sequential write to file
  169.   21   --  random read from file
  170.   22   --  random write to file
  171.   23   --  determine file size
  172.   24   --  set random record
  173. In addition to the CP/M compatible services, DOS also offers some special-
  174. ized services which have been available in all releases of DOS.  These
  175. include
  176.   27   --  multi-record random read.
  177.   28   --  multi-record random write.
  178.   29   --  parse filename
  179.   2A-2D -- get and set date and time
  180. All of the calls mentioned above which have anything to do with files make
  181. use of a data area called the "FILE CONTROL BLOCK" (FCB).  The FCB is any-
  182. where from 33 to 37 bytes long depending on how it is used.  You are
  183. responsible for creating an FCB and filling in the first 12 bytes, which
  184. contain a drive code, a file name, and an extension.
  185. When you open the FCB, the system fills in the next 20 bytes, which
  186. includes a logical record length.  The initial lrecl is always 128 bytes,
  187. to achieve CP/M compatibility.  The system also provides other useful
  188. information such as the file size.
  189.  
  190. IBM PC Assembly Language Tutorial                                        13
  191.  
  192.  
  193. After you have opened the FCB, you can change the logical record length.
  194. If you do this, your program is no longer CP/M compatible, but that doesn't
  195. make it a bad thing to do.  DOS documentation suggests you use a logical
  196. record length of one for maximum flexibility.  This is usually a good
  197. recommendation.
  198. To perform actual I/O to a file, you eventually need to fill in byte 33 or
  199. possibly bytes 34-37 of the FCB.  Here you supply information about the
  200. record you are interested in reading or writing.  For the most part, this
  201. part of the interface is compatible with CP/M.
  202. In general, you do not need to (and should not) modify other parts of the
  203. FCB.
  204. The FCB is pretty well described in appendix E of the DOS manual.
  205. Beginning with DOS 2.0, there is a whole new system of calls for managing
  206. files which don't require that you build an FCB at all.  These calls are
  207. quite incompatible with CP/M and also mean that your program cannot run
  208. under older releases of DOS.  However, these calls are very nice and easy
  209. to use.  They have these characteristics
  210. 1.  To open, create, delete, or rename a file, you need only a character
  211.     string representing its name.
  212. 2.  The open and create calls return a 16 bit value which is simply placed
  213.     in the BX register on subsequent calls to refer to the file.
  214. 3.  There is not a separate call required to specify the data buffer.
  215. 4.  Any number of bytes can be transfered on a single call; no data area
  216.     must be manipulated to do this.
  217. The "new" DOS calls also include comprehensive functions to manipulate the
  218. new chained directory structure and to allocate and free memory.
  219.  
  220. Learning the assembler
  221. ______________________
  222. Learning the assembler
  223. Learning the assembler
  224. Learning the assembler
  225. It is my feeling that many people can teach themselves to use the assembler
  226. by reading the MACRO Assembler manual if
  227. 1.  You have read and understood a book like Morse and thus have a feeling
  228.     for the instruction set
  229. 2.  You know something about DOS services and so can communicate with the
  230.     keyboard and screen and do something marginally useful with files.  In
  231.     the absence of this kind of knowledge, you can't write meaningful prac-
  232.     tice programs and so will not progress.
  233. 3.  You have access to some good examples (the ones supplied with the
  234.     assembler are not good, in my opinion.  I will try to supply you with
  235.     some more relevant ones.
  236. IBM PC Assembly Language Tutorial                                        14
  237.  
  238.  
  239. 4.  You ignore the things which are most confusing and least useful.  Some
  240.     of the most confusing aspects of the assembler include the facilities
  241.     combining segments.  But, you can avoid using all but the simplest of
  242.     these facilities in many cases, even while writing quite substantial
  243.     applications.
  244. 5.  The easiest kind of assembler program to write is a COM program.  They
  245.     might seem harder, at first, then EXE programs because there is an
  246.     extra step involved in creating the executable file, but COM programs
  247.     are structurally very much simpler.
  248. At this point, it is necessary to talk about COM programs and EXE programs.
  249. As you probably know, DOS supports two kinds of executable files.  EXE pro-
  250. grams are much more general, can contain many segments, and are generally
  251. built by compilers and sometimes by the assembler.  If you follow the lead
  252. given by the samples distributed with the assembler, you will end up with
  253. EXE programs.  A COM program, in contrast, always contains just one
  254. segment, and receives control with all four segment registers containing
  255. the same value.  A COM program, thus, executes in a simplified environment,
  256. a 64K address space.  You can go outside this address space simply by tem-
  257. porarily changing one segment register, but you don't have to, and that is
  258. the thing which makes COM programs nice and simple.  Let's look at a very
  259. simple one.
  260. The classic text on writing programs for the C language says that the first
  261. thing you should write is a program which says
  262.       HELLO, WORLD.
  263. when invoked.  What's sauce for C is sauce for assembler, so let's start
  264. with a HELLO program of our own.  My first presentation of this will be
  265. bare bones, not stylistically complete, but just an illustration of what an
  266. assembler program absolutely has to have:
  267. HELLO  SEGMENT                  ;Set up HELLO code and data section
  268.        ASSUME CS:HELLO,DS:HELLO ;Tell assembler about conditions at entry
  269.        ORG  100H                ;A .COM program begins with 100H byte prefix
  270. MAIN:  JMP  BEGIN               ;Control must start here
  271. MSG    DB   'Hello, world.$'    ;But it is generally useful to put data first
  272. BEGIN: MOV  DX,OFFSET MSG       ;Let DX --> message.
  273.        MOV  AH,9                ;Set DOS function code for printing a message
  274.        INT  21H                 ;Invoke DOS
  275.        RET                      ;Return to system
  276. HELLO  ENDS                     ;End of code and data section
  277.         END  MAIN                 ;Terminate assembler and specify entry point
  278. First, let's attend to some obvious points.  The macro assembler uses the
  279. general form
  280.    name    opcode    operands
  281. Unlike the 370 assembler, though, comments are NOT set off from operands by
  282. blanks.  The syntax uses blanks as delimiters within the operand field (see
  283. line 6 of the example) and so all comments must be set off by semi-colons.
  284. IBM PC Assembly Language Tutorial                                        15
  285.  
  286.  
  287. Line comments are frequently set off with a semi-colon in column 1.  I use
  288. this approach for block comments too, although there is a COMMENT statement
  289. which can be used to introduce a block comment.
  290. Being an old 370 type, I like to see assembler code in upper case, although
  291. my comments are mixed case.  Actually, the assembler is quite happy with
  292. mixed case anywhere.
  293. As with any assembler, the core of the opcode set consists of opcodes which
  294. generate machine instructions but there are also opcodes which generate
  295. data and ones which function as instructions to the assembler itself, some-
  296. times called pseudo-ops.  In the example, there are five lines which gener-
  297. ate machine code (JMP, MOV, MOV, INT, RET), one line which generates data
  298. (DB) and five pseudo-ops (SEGMENT, ASSUME, ORG, ENDS, and END).
  299. We will discuss all of them.
  300. Now, about labels.  You will see that some labels in the example end in a
  301. colon and some don't.  This is just a bit confusing at first, but no real
  302. mystery.  If a label is attached to a piece of code (as opposed to data),
  303. then the assembler needs to know what to do when you JMP to or CALL that
  304. label.  By convention, if the label ends in a colon, the assembler will use
  305. the NEAR form of JMP or CALL.  If the label does not end in a colon, it
  306. will use the FAR form.  In practice, you will always use the colon on any
  307. label you are jumping to inside your program because such jumps are always
  308. NEAR; there is no reason to use a FAR jump within a single code section.  I
  309. mention this, though, because leaving off the colon isn't usually trapped
  310. as a syntax error, it will generally cause something more abstruse to go
  311. wrong.
  312. On the other hand, a label attached to a piece of data or a pseudo-op never
  313. ends in a colon.
  314. Machine instructions will generally take zero, one or two operands.  Where
  315. there are two operands, the one which receives the result goes on the left
  316. as in 370 assembler.
  317. I tried to explain this before, now maybe it will be even clearer:  there
  318. are many more 8086 machine opcodes then there are assembler opcodes to rep-
  319. resent them.  For example, there are five kinds of JMP, four kinds of CALL,
  320. two kinds of RET, and at least five kinds of MOV depending on how you count
  321. them.  The macro assembler makes a lot of decisions for you based on the
  322. form taken by the operands or on attributes assigned to symbols elsewhere
  323. in your program.  In the example above, the assembler will generate the
  324. NEAR DIRECT form of JMP because the target label BEGIN labels a piece of
  325. code instead of a piece of data (this makes the JMP DIRECT) and ends in a
  326. colon (this makes the JMP NEAR).  The assembler will generate the immediate
  327. forms of MOV because the form OFFSET MSG refers to immediate data and
  328. because 9 is a constant.  The assembler will generate the NEAR form of RET
  329. because that is the default and you have not told it otherwise.
  330. The DB (define byte) pseudo-op is an easy one:  it is used to put one or
  331. more bytes of data into storage.  There is also a DW (define word)
  332. pseudo-op and a  DD (define doubleword) pseudo-op;  in the PC MACRO assem-
  333. bler, the fact that a label refers to a byte of storage, a word of storage,
  334. IBM PC Assembly Language Tutorial                                        16
  335.  
  336.  
  337. or a doubleword of storage can be very significant in ways which we will
  338. see presently.
  339. About that OFFSET operator, I guess this is the best way to make the point
  340. about how the assembler decides what instruction to assemble:  an analogy
  341. with 370 assembler:
  342.   PLACE    DC   ......
  343.            ...
  344.            LA   R1,PLACE
  345.            L    R1,PLACE
  346. In 370 assembler, the first instruction puts the address of label PLACE in
  347. register 1, the second instruction puts the contents of storage at label
  348. PLACE in register 1.  Notice that two different opcodes are used.  In the
  349. PC assembler, the analogous instructions would be
  350.   PLACE    DW   ......
  351.            ...
  352.            MOV  DX,OFFSET PLACE
  353.            MOV  DX,PLACE
  354. If PLACE is the label of a word of storage, then the second instruction
  355. will be understood as a desire to fetch that data into DX.  If X is a
  356. label, then "OFFSET X" means "the ordinary number which represents X's off-
  357. set from the start of the segment."  And, if the assembler sees an ordinary
  358. number, as opposed to a label, it uses the instruction which is equivalent
  359. to LA.
  360. If PLACE were the label of a DB pseudo-op, instead of a DW, then
  361.            MOV  DX,PLACE
  362. would be illegal.  The assembler worries about length attributes of its
  363. operands.
  364. Next, numbers and constants in general.  The assembler's default radix is
  365. decimal.  You can change this, but I don't recommend it.  If you want to
  366. represent numbers in other forms of notation such as hex or bit, you gener-
  367. ally use a trailing letter.  For example,
  368.            21H
  369.   is hexidecimal 21,
  370.            00010000B
  371.   is the eight bit binary number pictured.
  372. The next elements we should point to are the SEGMENT...ENDS pair and the
  373. END instruction.  Every assembler program has to have these elements.
  374. SEGMENT tells the assembler you are starting a section of contiguous mate-
  375. rial (code and/or data).  The symmetrically named ENDS statement tells the
  376. assembler you are finished with a section of contiguous material.  I wish
  377. they didn't use the word SEGMENT in this context.  To me, a "segment" is a
  378. hardware construct:  it is the 64K of real storage which becomes address-
  379. able by virtue of having a particular value in a segment register.  Now, it
  380. IBM PC Assembly Language Tutorial                                        17
  381.  
  382.  
  383. is true that the "segments" you make with the assembler often correspond to
  384. real hardware "segments" at execution time.  But, if you look at things
  385. like the GROUP and CLASS options supported by the linker, you will discover
  386. that this correspondence is by no means exact.  So, at risk of maybe con-
  387. fusing you even more, I am going to use the more informal term "section" to
  388. refer to the area set off by means of the SEGMENT and ENDS instructions.
  389. The sections delimited by SEGMENT...ENDS pairs are really a lot like CSECTs
  390. and DSECTs in the 370 world.
  391. I strongly recommend that you be selective in your study of the SEGMENT
  392. pseudo-op as described in the manual.  Let me just touch on it here.
  393.   name     SEGMENT
  394.   name     SEGMENT  PUBLIC
  395.   name     SEGMENT  AT  nnn
  396. Basically, you can get away with just the three forms given above.  The
  397. first form is what you use when you are writing a single section of assem-
  398. bler code which will not be combined with other pieces of code at link
  399. time.   The second form says that this assembly only contains part of the
  400. section;  other parts might be assembled separately and combined later by
  401. the linker.
  402. I have found that one can construct reasonably large modular applications
  403. in assembler by simply making every assembly use the same segment name and
  404. declaring the name to be PUBLIC each time.  If you read the assembler and
  405. linker documentation, you will also be bombarded by information about more
  406. complex options such as the GROUP statement and the use of other "combine
  407. types" and "classes."  I don't recommend getting into any of that.  I will
  408. talk more about the linker and modular construction of programs a little
  409. later.  The assembler manual also implies that a STACK segment is required.
  410. This is not really true.  There are numerous ways to assure that you have a
  411. valid stack at execution time.
  412. Of course, if you plan to write applications in assembler which are more
  413. than 64K in size, you will need more than what I have told you; but who is
  414. really going to do that?  Any application that large is likely to be coded
  415. in a higher level language.
  416. The third form of the SEGMENT statement makes the delineated section into
  417. something like a "DSECT;" that is, it doesn't generate any code, it just
  418. describes what is present somewhere already in the computer's memory.
  419. Sometimes the AT value you give is meaningful.  For example, the BIOS work
  420. area is located at location 40 hex.  So, you might see
  421.   BIOSAREA  SEGMENT AT 40H      ;Map BIOS work area
  422.             ORG  BIOSAREA+10H
  423.   EQUIP     DB   ?              ;Location of equipment flags, first byte
  424.   BIOSAREA  ENDS
  425. in a program which was interested in mucking around in the BIOS work area.
  426. At other times, the AT value you give may be arbitrary, as when you are
  427. mapping a repeated control block:
  428. IBM PC Assembly Language Tutorial                                        18
  429.